#include "event_base.h"



namespace xge{
namespace event{

  // EventIdentity class is simply a wrapper class , or just a pointer class
  // So , in fact , the using class like Event will not need to know this class
  // indeed .

  class EventIdentity {};

  // Implementation of trigger 

  bool Trigger::AddTriggerEvent( TriggerEvent* event , bool force ) {
    // Add a trigger should first testing this even is addable or not
    if( event->trigger_ != NULL ) {
      // If the user do not want to touch the inserted trigger 
      if( !force )
        return false;
      // This event has been binded to a existed event before 
      // Therefore , we just remove this trigger from the target
      // trigger list and make it free 
      event->trigger_->RemoveTriggerEvent(event);
      event->trigger_->Drop();
    }

    // Increasing the internal reference count
    this->Grab();
    event->trigger_ = this ;

    // Add this event internally to the event list
    event->Grab();
    event->id_ = trigger_event_list_.insert( trigger_event_list_.end() , event );

    // Now lets adjust the trigger life time by this trigger event 
    if( life_time() >=0 ) {
      // The trigger is not assign a life time or just have assign a finite
      // life time 
      if( life_time() < event->life_time() ) {
        // Our life time is shorter than the target event life time
        set_life_time( event->life_time() );
      } else {
        if( event->life_time() <0 ) {
          // Make our life time infinite since this event
          // has its infinite life time .
          set_life_time(-1);
        }
      }
    }

    return true;
  }


  Trigger::TriggerEventIdentity Trigger::RemoveTriggerEventInternal( TriggerEvent* event ) {
    TriggerEventIdentity ret;
    // Now we just need to remove this event from our list
    // We push a id value into this id tag for this will 
    // help us to implement OnLoop function more quickly !
    ret = trigger_event_list_.erase( event->id_ );
    event->Drop();
    // Drop the parent reference count
    Drop();
    event->trigger_ = NULL;
    return ret;
  }

  bool Trigger::RemoveTriggerEvent( TriggerEvent* event ) {
    //Check weather this event is in this trigger
    if( event->trigger_ != this )
      return false;
    //Remove the trigger event 
    RemoveTriggerEventInternal(event);
    return true;
  }


  void Trigger::OnLoop( const Timer::tick_t& time_diff ) {
    // Now testing if we really need to trigger the whole work now
    if( !IsOn(time_diff) ) {
      ++free_loop_;
      elapsed_time_+= time_diff;
      return ;
    }
    // Now testing if we really  need to do the triggering here 
    if( trigger_event_list_.empty() ) {
      set_life_time(0);
      return;
    }
    // Now do the real trigger event looping 
    TriggerEventList::iterator ib = trigger_event_list_.begin() ,
      ie = trigger_event_list_.end();

    for( ; ib != ie ; ) {
      (*ib)->OnEvent( elapsed_time_ , free_loop_ );
      // Decrease the event life time counter
      if( (*ib)->life_time_ >0 )
        --((*ib)->life_time_);
      // Testing if this event has to be deleted now
      if( (*ib)->life_time_ == 0 ) {
        ib = RemoveTriggerEventInternal( *ib );
      } else {
        if( !(*ib)->Reset() ) {
          ib = RemoveTriggerEventInternal( *ib );
        } else {
          ++ib;
        }
      }
    }
  }

  bool Trigger::Reset() {
    free_loop_ = 0;
    return true;
  }

  // The trigger ctor will initialized this trigger as 
  // 0 life time trigger !
  Trigger::Trigger() : Event(0) , elapsed_time_(0) , free_loop_(0) {}
  // Drop all the memory internally here 
  void Trigger::ClearTriggerEvent() {
    TriggerEventList::iterator ib = trigger_event_list_.begin() ,
      ie = trigger_event_list_.end();
    // Drop the reference counter 
    for( ; ib != ie ; ) {
      ib = RemoveTriggerEventInternal( *ib );
    }
  }


  // Implementation of EventManager

  bool EventManager::AddEvent( Event* event ) {
    // If the id_ is not a null pointer which means the
    // event has been added into the event manager , so
    // we do not need to add this event again !
    if( event->id_ != NULL )
      return false;
    // The event has not been added to the event manager before
    RealEventIdentity id = event_list_.insert( event_list_.end() , EventWrapper( event) );
    // Now lets make the event point to the right place 
    (*id).id = id;
    // Casting the internal tag into the common tag representation 
    event->id_ = (EventIdentity*)(&((*id).id));
    // Ok now , we have done all thing 
    return true;
  }

  EventManager::RealEventIdentity EventManager::RemoveEventInternal( Event* event ) {
    // Fetch the tag
    RealEventIdentity id = *((RealEventIdentity*)event->id_);
    // Remove it 
    RealEventIdentity ret = event_list_.erase( id );
    return ret;
  }

  EventManager::EventWrapper::EventWrapper(Event* eve ) {
    // grab the internal reference for this event
    eve->Grab(); 
    this->event = eve;
  }

  EventManager::EventWrapper::~EventWrapper() {
    event->id_ = NULL;
    event->Drop();
  }

  EventManager::EventWrapper::EventWrapper( const EventWrapper& wrapper ) {
    // This is typically very easy to get into false 
    wrapper.event->Grab();
    event = wrapper.event;
    // OK now 
  }


  void EventManager::ClearEvent() {
    RealEventIdentity ib = event_list_.begin() ,
      ie = event_list_.end();
    for( ; ib != ie ; ) {
      ib = RemoveEventInternal( (*ib).event );
    }
  }

  void EventManager::Loop( const Timer::tick_t& time_diff ) {
    // Checking the FPS
    cur_time_ += time_diff ;
    if( cur_time_ > time_ ) {
      // looping the event 
      RealEventIdentity ib = event_list_.begin() ,
        ie = event_list_.end();
      for( ; ib != ie ; ) {

        (*ib).event->OnLoop(time_);
        // Using the test to avoid the situation that the timer has been manually
        // set to zero , and when you use the minus 1 , the event now change to
        // permanent event now .
        if( (*ib).event->life_time_ >0 )
          --((*ib).event->life_time_);
        // Testing if the life time has reaches its limitation , when this happens
        // the event should be expired !
        if( (*ib).event->life_time_ == 0 ) {
          ib = RemoveEventInternal( (*ib).event );
        } else {
          if( !(*ib).event->Reset() ) {
            // The event can not reset here 
            ib = RemoveEventInternal( (*ib).event );
          } else {
            ++ib;
          }
        }
      }
      cur_time_ -= time_;
    }
  }



  


}// namespace xge
}// namespace event 